package com.ruoyi.web.controller.tool;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UrlProcessorTest {
    private static final String EXCEL_PATH = "D:\\pthdProject\\20250326.xlsx";
    private static final String OUTPUT_PATH = "D:\\pthdProject\\output.xlsx";
    private static final String OPENAI_KEY = "sk-787c7a30e78e43c294445914a3e49d8f";
    private static final String BASE_URL = "https://www.bjtth.org";
    private static final int MAX_CONTENT_LENGTH = 500;

    public static void main(String[] args) {
        try {
            List<UrlData> urlList = readExcel();
            processUrls(urlList);
            writeExcel(urlList);
            System.out.println("处理完成！结果保存在: " + OUTPUT_PATH);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 读取Excel文件
    private static List<UrlData> readExcel() throws Exception {
        List<UrlData> dataList = new ArrayList<>();
        ObjectMapper mapper = new ObjectMapper();

        try (FileInputStream fis = new FileInputStream(EXCEL_PATH);
             Workbook workbook = new XSSFWorkbook(fis)) {
            Sheet sheet = workbook.getSheetAt(0);

            // 找到"info"列的索引
            Row headerRow = sheet.getRow(0);
            if (headerRow == null) {
                throw new RuntimeException("Excel文件没有标题行");
            }

            int infoColumnIndex = -1;
            for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                Cell cell = headerRow.getCell(i);
                if (cell != null && cell.getCellType() == CellType.STRING &&
                    "info".equalsIgnoreCase(cell.getStringCellValue())) {
                    infoColumnIndex = i;
                    break;
                }
            }

            if (infoColumnIndex == -1) {
                throw new RuntimeException("未找到'info'列，请检查Excel文件格式");
            }

            System.out.println("找到'info'列，索引为: " + infoColumnIndex);

            // 从第二行开始读取数据
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) continue;

                Cell cell = row.getCell(infoColumnIndex);
                if (cell == null) continue;

                try {
                    // 确保单元格是字符串类型
                    String jsonValue;
                    if (cell.getCellType() == CellType.STRING) {
                        jsonValue = cell.getStringCellValue();
                    } else {
                        // 尝试转换其他类型为字符串
                        DataFormatter formatter = new DataFormatter();
                        jsonValue = formatter.formatCellValue(cell);
                        System.out.println("警告：第" + (i+1) + "行的单元格不是字符串类型，已尝试转换");
                    }

                    if (jsonValue == null || jsonValue.trim().isEmpty()) {
                        continue;
                    }

                    JsonNode jsonNode = mapper.readTree(jsonValue);
                    if (jsonNode.has("url")) {
                        String url = jsonNode.get("url").asText("");
                        if (!url.isEmpty()) {
                            // 添加域名前缀
                            if (!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://")) {
                                url = BASE_URL + (url.startsWith("/") ? "" : "/") + url;
                            }
                            dataList.add(new UrlData(url));
                            System.out.println("添加URL: " + url);
                        } else {
                            System.out.println("警告：第" + (i+1) + "行的JSON中URL为空");
                        }
                    } else {
                        System.out.println("警告：第" + (i+1) + "行的JSON中没有url字段");
                    }
                } catch (Exception e) {
                    System.err.println("处理第" + (i+1) + "行时出错: " + e.getMessage());
                }
            }
        }

        System.out.println("共读取到 " + dataList.size() + " 个有效URL");
        return dataList;
    }

    // 处理所有URL
    private static void processUrls(List<UrlData> urlList) throws Exception {
        int i=0;
        try (CloseableHttpClient httpClient = HttpClientBuilder.create()
                .setMaxConnTotal(10)
                .setMaxConnPerRoute(5)
                .build()) {

            ObjectMapper mapper = new ObjectMapper();
            for (UrlData data : urlList) {
                try {
                        System.out.println("处理URL: " + data.url);
                        String content = fetchUrlContent(httpClient, data.url);
                        String description = getAiDescription(httpClient, mapper, content);
                        data.setDescription(description);
                        // 添加处理间隔，避免请求过于频繁
                        Thread.sleep(1000);
                } catch (Exception e) {
                    data.setDescription("处理失败: " + e.getMessage());
                    System.err.println("处理 URL " + data.url + " 时出错: " + e.getMessage());

                }
            }
        }
    }
    private static String fetchUrlContent(CloseableHttpClient client, String url) throws Exception {
        HttpGet request = new HttpGet(url);
        request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
        request.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        request.setHeader("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");

        // 设置超时
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(10_000)
                .setSocketTimeout(10_000)
                .setConnectionRequestTimeout(5000)
                .build();
        request.setConfig(config);

        try (CloseableHttpResponse response = client.execute(request)) {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode >= 400) {
                throw new RuntimeException("HTTP错误: " + statusCode);
            }

            HttpEntity entity = response.getEntity();
            if (entity == null) {
                throw new RuntimeException("响应内容为空");
            }

            String charset = detectCharset(entity, response);
            String content = EntityUtils.toString(entity, charset);

            // 清理内容，移除控制字符和一些特殊字符
            content = content.replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", "");

            // 提取纯文本内容，去除HTML标签
            content = extractTextFromHtml(content);

            // 限制内容长度
            if (content.length() > MAX_CONTENT_LENGTH) {
                content = content.substring(0, MAX_CONTENT_LENGTH);
            }

            return content;
        }
    }

    // 编码检测方法
    private static String detectCharset(HttpEntity entity, HttpResponse response) {
        // 优先级1：从Content-Type头获取
        Header contentTypeHeader = entity.getContentType();
        if (contentTypeHeader != null) {
            ContentType contentType = ContentType.parse(contentTypeHeader.getValue());
            if (contentType.getCharset() != null) {
                return contentType.getCharset().name();
            }
        }

        // 优先级2：从HTML meta标签中提取（更准确但需要解析）
        // 注意：我们不能直接消费实体内容，因为这会关闭流
        // 这里我们跳过此步骤，直接使用默认编码

        // 优先级3：使用UTF-8作为默认
        return "UTF-8";
    }

    // 解析HTML meta标签中的编码
    private static String parseHtmlCharset(String html) {
        Pattern pattern = Pattern.compile(
                "<meta.*?charset\\s*=\\s*[\"']?([^\"'>]+)",
                Pattern.CASE_INSENSITIVE
        );
        Matcher matcher = pattern.matcher(html);
        if (matcher.find()) {
            return matcher.group(1).toUpperCase()
                    .replace("UTF8", "UTF-8")
                    .replace("GB2312", "GBK");
        }
        return null;
    }

    // 从HTML中提取纯文本内容
    private static String extractTextFromHtml(String html) {
        if (html == null || html.isEmpty()) {
            return "";
        }

        // 移除脚本和样式
        html = html.replaceAll("<script[^>]*>.*?</script>", " ")
                   .replaceAll("<style[^>]*>.*?</style>", " ")
                   .replaceAll("<!--.*?-->", " ");

        // 移除HTML标签
        html = html.replaceAll("<[^>]+>", " ");

        // 替换多个空白字符为单个空格
        html = html.replaceAll("\\s+", " ").trim();

        // 解码HTML实体
        html = html.replace("&nbsp;", " ")
                   .replace("&lt;", "<")
                   .replace("&gt;", ">")
                   .replace("&amp;", "&")
                   .replace("&quot;", "\"")
                   .replace("&apos;", "'");

        return html;
    }

    // 获取网页内容
//    private static String fetchUrlContent(CloseableHttpClient client, String url) throws Exception {
//        HttpGet request = new HttpGet(url);
//        request.setHeader("User-Agent", "Mozilla/5.0");
//
//        // 设置超时（10秒）
//        RequestConfig config = RequestConfig.custom()
//                .setConnectTimeout(10_000)
//                .setSocketTimeout(10_000)
//                .build();
//        request.setConfig(config);
//
//        HttpResponse response = client.execute(request);
//        int statusCode = response.getStatusLine().getStatusCode();
//        if (statusCode >= 400) {
//            throw new RuntimeException("HTTP错误: " + statusCode);
//        }
//
//        String content = EntityUtils.toString(response.getEntity());
//        return   content;
//    }

    // 获取AI描述
    private static String getAiDescription(CloseableHttpClient client, ObjectMapper mapper, String content) throws Exception {
        HttpPost request = new HttpPost("https://api.deepseek.com/v1/chat/completions");
        request.setHeader("Content-Type", "application/json");
        request.setHeader("Authorization", "Bearer " + OPENAI_KEY);

        // 清理和转义内容
        content = content.replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", "")
                         .replace("\\", "\\\\")
                         .replace("\"", "\\\"")
                         .replace("\b", "\\b")
                         .replace("\f", "\\f")
                         .replace("\n", "\\n")
                         .replace("\r", "\\r")
                         .replace("\t", "\\t");

        // 手动构建JSON请求体
        String jsonBody = String.format(
            "{\"model\":\"deepseek-chat\",\"messages\":[" +
            "{\"role\":\"system\",\"content\":\"依据网页展示的信息撰写描述。输出要求 描述需准确概括该栏目网页呈现的主要内容、核心信息，以及对用户的价值或作用。 描述语言要逻辑清晰，准确无误。不需要包含技术方面，只分析文本内容。\"}," +
            "{\"role\":\"user\",\"content\":\"网页内容片段：%s\"}]}", content);

        request.setEntity(new StringEntity(jsonBody, "UTF-8"));

        try {
            HttpResponse response = client.execute(request);
            HttpEntity entity = response.getEntity();
            if (entity == null) {
                throw new RuntimeException("AI API响应内容为空");
            }
            String responseBody = EntityUtils.toString(entity);

            // 打印响应体以进行调试
            System.out.println("API Response: " + responseBody);

            JsonNode root = mapper.readTree(responseBody);
            if (root.has("error")) {
                throw new RuntimeException("API错误: " + root.path("error").path("message").asText());
            }
            if (!root.has("choices") || root.path("choices").size() == 0) {
                throw new RuntimeException("AI API返回数据格式错误: " + responseBody);
            }
            return root.path("choices").get(0).path("message").path("content").asText();
        } catch (Exception e) {
            e.printStackTrace();  // 打印完整的堆栈跟踪
            return "处理失败: " + e.getMessage();
        }
    }

    // 写入结果文件
    private static void writeExcel(List<UrlData> dataList) throws Exception {
        try (Workbook workbook = new XSSFWorkbook();
             FileOutputStream fos = new FileOutputStream(OUTPUT_PATH)) {
            Sheet sheet = workbook.createSheet("Results");

            // 创建标题行
            Row headerRow = sheet.createRow(0);
            headerRow.createCell(0).setCellValue("URL");
            headerRow.createCell(1).setCellValue("描述");

            // 填充数据
            int rowNum = 1;
            for (UrlData data : dataList) {
                Row row = sheet.createRow(rowNum++);
                row.createCell(0).setCellValue(data.url);
                row.createCell(1).setCellValue(data.description);
            }
            workbook.write(fos);
        }
    }

    // 数据承载类
    static class UrlData {
        String url;
        String description;

        public UrlData(String url) {
            this.url = url;
        }

        public void setDescription(String desc) {
            this.description = desc;
        }
    }
}